home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-01 / commtc2.zip / COMM_TC2.C < prev    next >
Text File  |  1993-01-04  |  55KB  |  493 lines

  1. /*                                                                           */ /*-The comment column will  */
  2. /* Written by:  Kevin R. Bulgrien         Version 1.00 completed 02/01/89    */ /* be used to tell what the */
  3. /*                                                                           */ /* program is doing where   */
  4. /* Contact at:  LeTourneau College        LeTourneau College BBS             */ /* it is not self-evident   */
  5. /*              Microcomputer Services    2400/1200/300 Baud                 */ /*                          */
  6. /*              P.O. Box 7001             (214) 237-2742                     */ /* Yes, it is wider than 80 */
  7. /*              Longview, TX  75607                                          */ /* columns so you will need */
  8. /*                                                                           */ /* to use compressed print  */
  9. /* This program works with Turbo C 2.0. See Comm_TC2.DOC for instructions.   */ /* to print it out          */
  10. /* Comm_TP3 & Comm_TP4 by the same author, work with Turbo Pascal 3, 4 & 5   */ /*                          */
  11.                                                                                 /* Don't complain too much  */
  12. /* This program was compiled and tested with the Small Memory Model.  Stack  */ /* as code documentation is */
  13. /* checking MUST be turned off for the interrupt routine to work correctly.  */ /* far easier to read when  */
  14.                                                                                 /* it is not intermingled   */
  15. /* Version History                                                           */ /* with code...             */
  16. /*                                                                           */ /*                          */
  17. /*  1.00  02/89 Original code uploaded to GEnie's Borland Roundtable         */ /*                          */
  18.                                                                                 /*                          */
  19. #include <dos.h>                                                                /*-The standard headers     */
  20. #include <bios.h>                                                               /* needed for compilation   */
  21. #include <conio.h>                                                              /*                          */
  22. #include <stdio.h>                                                              /*                          */
  23. #include <stdlib.h>                                                             /*                          */
  24.                                                                                 /*                          */
  25. #define MaxSize 512                                                             /*-Maximum receive buffer   */
  26.                                                                                 /* size in bytes            */
  27. enum BaudType { B110,B150,B300,B600,B1200,B2400,B4800,B9600,B19200,B38400 };    /*-Baud rates supported     */
  28.                                                                                 /*                          */
  29. enum ParityType { None, Odd, Null, Even, MarkOff, Mark, SpaceOff, Space };      /*-Parity types supported   */
  30.                                                                                 /*                          */
  31. /* Mark parity means that parity is enabled and the parity bit is always set to 0.  Space parity means that */
  32. /* parity is enabled and the parity bit is always set to 1.  MarkOff and SpaceOff indicate that Mark or     */
  33. /* Space parity is chosen but parity is disabled.  Functionally they are equivalent to NONE - as is NULL.   */
  34.                                                                                 /*                          */
  35. enum Boolean { FALSE, TRUE };                                                   /*-I like this for storing  */
  36.                                                                                 /* logical values           */
  37. typedef unsigned char byte;                                                     /*                          */
  38. typedef unsigned int word;                                                      /*                          */
  39.                                                                                 /*                          */
  40. typedef struct                                                                  /* 8250 Communications Chip */
  41.           {                                                                     /* ------------------------ */
  42.             word THR;                                                           /* Transmit Holding Reg     */
  43.             word RHR;                                                           /* Receive Holding Register */
  44.             word DLL;                                                           /* Divisor Latch Reg LSB    */
  45.             word IER;                                                           /* Interrupt Enable Reg     */
  46.             word DLM;                                                           /* Divisor Latch Reg MSB    */
  47.             word IIR;                                                           /* Interrupt ID Register    */
  48.             word LCR;                                                           /* Line Control Register    */
  49.             word MCR;                                                           /* Modem Control Register   */
  50.             word LSR;                                                           /* Line Status Register     */
  51.             word MSR; } INS8250 [2];                                            /* Modem Status Register    */
  52.                                                                                 /*                          */
  53. typedef struct                                                                  /*-Used to hold the current */
  54.           {                                                                     /* settings of COM1 & COM2  */
  55.             byte Baud;                                                          /*                          */
  56.             byte Parity;                                                        /*                          */
  57.             byte Stop;                                                          /*                          */
  58.             byte Bits;  } ComSettingsType [2];                                  /*                          */
  59.                                                                                 /*                          */
  60. const INS8250 RS232 = {                                                         /*-COM1 addresses for 8250  */
  61.                         { 0x3F8, 0x3F8, 0x3F8, 0x3F9, 0x3F9,                    /* registers so they may be */
  62.                           0x3FA, 0x3FB, 0x3FC, 0x3FD, 0x3FE                     /* accessed by name         */
  63.                         },                                                      /*                          */
  64.                         { 0x2F8, 0x2F8, 0x2F8, 0x2F9, 0x2F9,                    /*-COM2 addressed for 8250  */
  65.                           0x2FA, 0x2FB, 0x2FC, 0x2FD, 0x2FE                     /* registers so they may be */
  66.                         }                                                       /* accessed by name         */
  67.                       };                                                        /*                          */
  68.                                                                                 /*                          */
  69. void interrupt (*OldIntVector [2]) ();                                          /*-Original COMx vectors    */
  70. enum Boolean IntInstalled [2];                                                  /*-TRUE if interrupt loaded */
  71. word InHead [2], InTail [2];                                                    /*-Input buffer indexes     */
  72. ComSettingsType ComSettings;                                                    /*-COMx line settings       */
  73. byte InBuffer [2] [MaxSize];                                                    /*-Input circular queue     */
  74. enum Boolean Carrier [2];                                                       /*-TRUE if Carrier Detected */
  75. byte CurrentCom;                                                                /*-COM port in use          */
  76. word MaxPorts;                                                                  /*-# of usable COM ports    */
  77.                                                                                 /*                          */
  78. /* This procedure sets up the selected COM port to the specified parameters.  The Com parameter specifies   */
  79. /* the port to set up.  It must be in the range 0 to 1, and is checked for errors.  The Baud parameter must */
  80. /* be in the range 0 to 9, and is not range checked. 1.5 stop bits are used when StopBits == 2 AND DataBits */
  81. /* == 5, but otherwise StopBits will set the correct number of stop bits in the range 1 to 2.  DataBits may */
  82. /* be set with 5 to 8 for the number of data bits to use.                                                   */
  83.                                                                                 /*                          */
  84. void SetupRS232 (byte Com, byte Baud, byte Parity, byte StopBits, byte DataBits)/*                          */
  85.   {                                                                             /*-These values set a baud  */
  86.     const word BaudTable [] = { 0x0417, 0x0300, 0x0180, 0x00C0, 0x0060,         /* rate for the 8250 when   */
  87.                                 0x0030, 0x0018, 0x000C, 0x0006, 0x0003 };       /* written to DLL & DLM     */
  88.     byte Parameters;                                                            /*-Temporary to calculate   */
  89.                                                                                 /* LCR register setting     */
  90.     if (Com < MaxPorts)                                                         /*-Check validity of Com    */
  91.       {                                                                         /*                          */
  92.         disable ();                                                             /*-Always when writing 8250 */
  93.         outportb (RS232 [Com].MCR, 0x00);                                       /*-DTR & RTS off/kill modem */
  94.         outportb (RS232 [Com].LCR, inportb (RS232 [Com].LCR) | 0x80);           /*-Allow access to DLL/DLM  */
  95.         outportb (RS232 [Com].DLL, BaudTable [Baud] & 0x00FF);                  /*-Set baud rate            */
  96.         outportb (RS232 [Com].DLM, (BaudTable [Baud] & 0xFF00) >> 0x08);        /*                          */
  97.         Parameters = (DataBits - 5) & 0x03;                                     /*-Build values to write to */
  98.         Parameters = Parameters | (((StopBits - 1) << 2) & 0x04);               /* Line Control Register    */
  99.         Parameters = Parameters | ((Parity << 3) & 0x38);                       /*                          */
  100.         outportb (RS232 [Com].LCR, Parameters);                                 /*-Set Parity/Data/Stop Bits*/
  101.         outportb (RS232 [Com].MCR, 0x0B);                                       /*-DTR & RTS back on        */
  102.         enable ();                                                              /*-Done writing to 8250 Regs*/
  103.       }                                                                         /*                          */
  104.     else printf ("\nError!  COM%u not available/n", Com);                       /*-Used for debugging while */
  105.   }                                                                             /* writing an application   */
  106.                                                                                 /*                          */
  107. /* This procedure handles interrupts from the 8250 communications chip.  All interrupt types are provided   */
  108. /* for though I only implemented the receive data interrupt and crudely used the modem status interrupt.    */
  109. /* The skeleton is there though, so you can write your own implementations for the interrupts.  Incoming    */
  110. /* data is stored in InBuffer if the buffer is not full - otherwise it is ignored. The buffer is full when  */
  111. /* (InTail [IntCom] + 1) % MaxSize == InHead [IntCom].  The buffer is empty when InTail [IntCom] == InHead  */
  112. /* [IntCom].  InTail [IntCom] is incremented so that it always points to where the next item will be put.   */
  113. /* Modem (port) status is monitored for Carrier Detect.  The global enum Boolean variable 'Carrier' always  */
  114. /* shows the status of each COM port if its interrupt handler is active.  TRUE == Carrier Detected and      */
  115. /* FALSE == No Carrier Detected.  This is done for programs that will use a modem for input.  NOTE: Stack   */
  116. /* checking must always be turned off in interrupt handlers.                                                */
  117.                                                                                 /*                          */
  118. void interrupt IntHandler ()                                                    /*                          */
  119. {                                                                               /*                          */
  120.   byte IntCom;                                                                  /*-COM port which caused an */
  121.                                                                                 /* interrupt                */
  122.   outportb (0x20, 0x0B);                                                        /*-Allow access to 8259 ISR */
  123.   IntCom = (2 - ((inportb (0x20) & 0x18) >> 3));                                /*-Detect interrupting port */
  124.   switch (inportb (RS232 [IntCom].IIR) & 0x06)                                  /*                          */
  125.   {                                                                             /*                          */
  126.     case 0 : Carrier[IntCom] = (0x80 & inportb(RS232[IntCom].MSR));             /*-Modem Status Change Int. */
  127.              break;                                                             /*-Save new Carrier status  */
  128.     case 2 : /* DO Nothing */;                                                  /*-Transmit Register empty  */
  129.              break;                                                             /*-Receive Register full    */
  130.     case 4 : outportb(RS232[IntCom].LCR,inportb(RS232[IntCom].LCR) & 0x7F);     /*-Allow THR/RHR/IER access */
  131.              if (((InTail [IntCom] + 1) % MaxSize) != InHead [IntCom])          /*                          */
  132.                {                                                                /*-If buffer is not full,   */
  133.                  InBuffer[IntCom][InTail[IntCom]] = inportb (RS232[IntCom].RHR);/* add the character & set  */
  134.                  InTail [IntCom] = (InTail [IntCom] + 1) % MaxSize;             /* the queue index pointer  */
  135.                }                                                                /*                          */
  136.              else if (inportb (RS232 [IntCom].RHR) == 0x00) /* DO Nothing */;   /*-If the buffer is full,   */
  137.              break;                                                             /* read & ignore character  */
  138.     case 6 : /* DO Nothing */;                                                  /*                          */
  139.              break;                                                             /*-Line Status Change Int.  */
  140.   }                                                                             /*                          */
  141.   outportb (0x20, 0x20);                                                        /*-Notify 8259 of interrupt */
  142. }                                                                               /* completion (nonspecific) */
  143.                                                                                 /*                          */
  144. /* This procedure installs and enables the specified serial port interrupt.  It also forces the appropriate */
  145. /* input buffer to the empty state.  Carrier is initialized to the current state of the Carrier Detect line */
  146. /* on the port.  The old serial port interrupt vector is saved so that it can be reinstalled when we remove */
  147. /* our serial port interrupt.  DTR and RTS are forced to the ready state & the 8250 interrupts are enabled  */
  148. /* by writing 0x0B to the MCR.  To enable all four types of 8250 interrupts, write 0x0F to the IER. (I used */
  149. /* 0x09 to only enable the Modem Status Change and Receive Buffer Full interrupts).  ORing 0xEF with I/O    */
  150. /* port 0x21 enables IRQ4 (COM1), while ORing 0xF7 enables IRQ3 (COM2).  Interrupts must be disabled during */
  151. /* the installation process since the 8250 & 8259 ports are being accessed.                                 */
  152.                                                                                 /*                          */
  153. void InstallInt (byte Com)                                                      /*                          */
  154. {                                                                               /*-Don't install twice or   */
  155.   if ((! IntInstalled [Com]) && (Com < MaxPorts))                               /* install for missing port */
  156.     {                                                                           /*                          */
  157.       disable ();                                                               /*                          */
  158.       InTail [Com] = 0;                                                         /*-Force input buffer empty */
  159.       InHead [Com] = 0;                                                         /*                          */
  160.       Carrier [Com] = ((0x80 & inportb (RS232 [Com].MSR)) == 0x80);             /*-Read Carrier Status      */
  161.       outportb (RS232 [Com].LCR, inportb (RS232 [Com].LCR) & 0x7F);             /*-Allow THR/RHR/IER access */
  162.       outportb (RS232 [Com].IER, 0x00);                                         /*-Disable 8250 interrupts  */
  163.       if (inportb (RS232 [Com].LSR) != 0) /* Nothing */;                        /*-Reset interrupts waiting */
  164.       if (inportb (RS232 [Com].RHR) != 0) /* Nothing */;                        /* to be processed          */
  165.       OldIntVector [Com] = getvect (0x0C - Com);                                /*-Save old interrupt vector*/
  166.       setvect (0x0C - Com, IntHandler);                                         /*-Load new interrupt vector*/
  167.       IntInstalled [Com] = TRUE;                                                /*                          */
  168.       switch (Com)                                                              /*                          */
  169.         {                                                                       /*                          */
  170.            case 0 : outportb (0x21, inportb (0x21) & 0xEF);                     /*-Enable 8259 IRQ4 (COM1)  */
  171.                     break;                                                      /*                          */
  172.            case 1 : outportb (0x21, inportb (0x21) & 0xF7);                     /*-Enable 8259 IRQ3 (COM2)  */
  173.           default : break;                                                      /*                          */
  174.         }                                                                       /*                          */
  175.       outportb (RS232 [Com].LCR, inportb (RS232 [Com].LCR) & 0x7F);             /*-Allow THR/RHR/IER access */
  176.       outportb (RS232 [Com].IER, 0x09);                                         /*-Enable 8250 interrupts   */
  177.       outportb (RS232 [Com].MCR, 0x0B);                                         /*-Set DTR & RTS so other   */
  178.       enable ();                                                                /* device knows we're ready */
  179.     }                                                                           /* to receive data          */
  180.   else                                                                          /*                          */
  181.     {                                                                           /*                          */
  182.       printf ("\nError!  COM%u ", Com + 1);                                     /*-Here for debugging use   */
  183.       if (IntInstalled [Com])                                                   /* Remove it if you want to */
  184.         puts ("interrupt already installed\n");                                 /*                          */
  185.       else                                                                      /*                          */
  186.         puts ("not available\n");                                               /*                          */
  187.     }                                                                           /*                          */
  188. }                                                                               /*                          */
  189.                                                                                 /*                          */
  190. /* This procedure removes the specified serial port interrupt & reinstalls the original interrupt vectors.  */
  191. /* DTR & RTS are set OFF and 8250 interrupts are disabled by writing 0x00 to the MCR.  All 8250 interrupt   */
  192. /* type are disabled by writing 0x00 to the IER.  ORing 0x10 with I/O port 0x21 disables IRQ4 (COM1), while */
  193. /* ORing 0x08 disables IRQ3 (COM2).  Interrupts must be disabled during this process.                       */
  194.                                                                                 /*                          */
  195. void RemoveInt (byte Com)                                                       /*                          */
  196. {                                                                               /*                          */
  197.   if (IntInstalled [Com])                                                       /*-Do not remove interrupt  */
  198.     {                                                                           /* if it was not installed  */
  199.       disable ();                                                               /*                          */
  200.       switch (Com)                                                              /*                          */
  201.         {                                                                       /*                          */
  202.           case 0 : outportb (0x21, inportb (0x21) | 0x10);                      /*-Disable 8259 IRQ4 (COM1) */
  203.                    break;                                                       /*                          */
  204.           case 1 : outportb (0x21, inportb (0x21) | 0x08);                      /*-Disable 8259 IRQ3 (COM2) */
  205.                    break;                                                       /*                          */
  206.         }                                                                       /*                          */
  207.       outportb (RS232 [Com].LCR, inportb (RS232 [Com].LCR) & 0x7F);             /*-Allow THR/RHR/IER access */
  208.       outportb (RS232 [Com].IER, 0x00);                                         /*-Disable 8250 interrupts  */
  209.       outportb (RS232 [Com].MCR, 0x00);                                         /*-Set DTR/RTS off. Remove  */
  210.       setvect (0x0C - Com, OldIntVector [Com]);                                 /* if modem shouldn't hang  */
  211.       IntInstalled [Com] = FALSE;                                               /* up when you RemoveInt    */
  212.       enable ();                                                                /*-setvect installed the    */
  213.     }                                                                           /* original interrupt vector*/
  214.   else printf ("\nError!  COM%u interrupt is not installed\n", Com+1);          /*-Used for debugging. It   */
  215. }                                                                               /* is optional.             */
  216.                                                                                 /*                          */
  217. /* This procedure writes character or string data to the serial port.  It does this by directly reading and */
  218. /* writing to the 8250 communications chip.  This is an example that may be modified to suit your purposes. */
  219. /* As is, it pauses the program while it sends the data.  If it cannot send a character after 65535 tries,  */
  220. /* it aborts the sending process.  This could easily be converted to a function that returns a enum Boolean */
  221. /* value TimeOut. The statement: (inportb (RS232 [Com].LSR) & 0x20) != 0x20 indicates when the THR is ready */
  222. /* for a new character to send.  CTS and DSR are not checked, but if you want to check for them (inportb    */
  223. /* (RS232 [Com].MSR) & 0x30) must equal 0x30.  Interrupts must be disabled while using the 8250 ports.  Com */
  224. /* is 0 for COM1 and 1 for COM2.  DataPtr is a pointer to a string.                                         */
  225.                                                                                 /*                          */
  226. void WriteCOM (byte Com, byte *DataPtr)                                         /*                          */
  227. {                                                                               /*                          */
  228.   enum Boolean TimeOut;                                                         /*-TRUE if unable to send   */
  229.   word TimeLoop;                                                                /*-Timeout counter          */
  230.                                                                                 /*                          */
  231.   TimeOut = FALSE;                                                              /*                          */
  232.   while (*DataPtr && ! TimeOut)                                                 /*-Send data one char at a  */
  233.     {                                                                           /* time unless timed out    */
  234.       TimeLoop = 0;                                                             /*                          */
  235.       while ((TimeLoop < 0xFFFF)&&((inportb (RS232 [Com].LSR) & 0x20) != 0x20)) /*-Do not send data if THR  */
  236.         TimeLoop += 1;                                                          /* is not empty yet         */
  237.       if (TimeLoop != 0xFFFF)                                                   /*                          */
  238.         {                                                                       /*                          */
  239.           disable ();                                                           /*                          */
  240.           outportb (RS232 [Com].LCR, inportb (RS232 [Com].LCR) & 0x7F);         /*-Allow THR/RHR/IER access */
  241.           outportb (RS232 [Com].THR, *DataPtr);                                 /*-Put data to send in THR  */
  242.           enable ();                                                            /*                          */
  243.           DataPtr++;                                                            /*-Advance string pointer   */
  244.         }                                                                       /*                          */
  245.       else                                                                      /*                          */
  246.         {                                                                       /*                          */
  247.           TimeOut = TRUE;                                                       /*-WriteCOM aborts if THR   */
  248.           printf ("\nTimeout on COM%u", Com);                                   /* takes too long to become */
  249.         }                                                                       /* empty                    */
  250.     }                                                                           /*                          */
  251. }                                                                               /*                          */
  252.                                                                                 /*                          */
  253. /* This function is an example of how to get a character from the serial port. As is, when the buffer is    */
  254. /* empty, it waits until a character arrives, so this will not work for the TTY emulation.  The interrupts  */
  255. /* are always disabled when the buffer pointers are checked or modified.  Beware! Do not completely disable */
  256. /* interrupts in the wait loop or else you never will get a character if there is not one there already.    */
  257.                                                                                 /*                          */
  258. byte ReadCOM (byte Com)                                                         /*                          */
  259. {                                                                               /*                          */
  260.   enum Boolean CharReady;                                                       /*-TRUE if there is data    */
  261.   byte DataByte;                                                                /*-Data buffer              */
  262.                                                                                 /*                          */
  263.   CharReady = FALSE;                                                            /*                          */
  264.   do                                                                            /*-Wait for data to arrive  */
  265.     {                                                                           /*                          */
  266.       disable ();                                                               /*                          */
  267.       CharReady = (InTail [Com] != InHead [Com]);                               /*-Check if the buffer is   */
  268.       enable ();                                                                /* empty or not             */
  269.     } while (! CharReady);                                                      /*                          */
  270.   disable ();                                                                   /*                          */
  271.   DataByte = InBuffer [Com] [InHead [Com]];                                     /*-Read the character       */
  272.   InHead [Com] = (InHead [Com] + 1) % MaxSize;                                  /*-Remove it from the input */
  273.   enable ();                                                                    /* buffer                   */
  274.   return (DataByte);                                                            /*-Return the character     */
  275. }                                                                               /*                          */
  276.                                                                                 /*                          */
  277. atexit_t RemoveIntOnExit (void)                                                 /*-VERY IMPORTANT! When the */
  278.   {                                                                             /* program quits normally   */
  279.     if (IntInstalled [0]) RemoveInt (0);                                        /* or abnormally, interrupt */
  280.     if (IntInstalled [1]) RemoveInt (1);                                        /* handlers are uninstalled */
  281.     printf ("\nAll interrupt handlers have been uninstalled\n");                /* automatically            */
  282.   }                                                                             /*                          */
  283.                                                                                 /*                          */
  284. /* End of RS-232 handler routines ---------- Start of TTY emulation routines */ /*                          */
  285.                                                                                 /*                          */
  286. /* A crude but effective procedure to allow the user to change settings of a COM port in use.  CurrentCom   */
  287. /* and ComSettings determine how the port is currently set up.  As the parameters are changed, ComSettings  */
  288. /* updated. Once again, keep in mind that the object of this program is not to provide a glamorous terminal */
  289. /* program.  Rather it serves as a simple model for those wanting to incorporate serial routines in their   */
  290. /* own programs.                                                                                            */
  291.                                                                                 /*                          */
  292. void SetUpPort (byte Com)                                                       /*                          */
  293. {                                                                               /*                          */
  294.   enum Boolean ResetPort;                                                       /*-TRUE if settings changed */
  295.   byte InkeyChr;                                                                /*-Keyboard input variable  */
  296.                                                                                 /*                          */
  297.   ResetPort = FALSE;                                                            /*                          */
  298.   printf ("\nCOM%u Setup\n\n", Com + 1);                                        /*-Identify port to change  */
  299.   puts ("0)  110           5)  2400\n1)  150           6)  4800");              /*                          */
  300.   puts ("2)  300           7)  9600\n3)  600           8) 19200");              /*-Select a baud rate       */
  301.   puts ("4) 1200           9) 38400\n");                                        /*                          */
  302.   printf ("Select a baud rate [%u]: ", ComSettings [Com] . Baud);               /*-Note that defaults are   */
  303.   do                                                                            /* allowed if you use <CR>  */
  304.     {                                                                           /* at any of the prompts.   */
  305.       InkeyChr = (byte) getch ();                                               /* The port is not reset    */
  306.     } while (((InkeyChr < 48) | (InkeyChr > 57)) & (InkeyChr != 0x0D));         /* unless the defaults are  */
  307.   printf ("%c\n\n", (byte) InkeyChr);                                           /* changed                  */
  308.   if (InkeyChr != 0x0D)                                                         /*                          */
  309.     {                                                                           /*                          */
  310.       ComSettings [Com] . Baud = InkeyChr - 48;                                 /*                          */
  311.       ResetPort = TRUE;                                                         /*                          */
  312.     }                                                                           /*                          */
  313.   puts ("0) None           2) None\n1) Odd            3) Even\n");              /*-Select a parity setting  */
  314.   printf ("Select a parity type [%u]: ", ComSettings [Com] . Parity);           /*                          */
  315.   do                                                                            /*                          */
  316.     {                                                                           /*                          */
  317.       InkeyChr = (byte) getch ();                                               /*                          */
  318.     } while (((InkeyChr < 48) | (InkeyChr > 51)) & (InkeyChr != 0x0D));         /*                          */
  319.   printf ("%c\n\n", (byte) InkeyChr);                                           /*                          */
  320.   if (InkeyChr != 0x0D)                                                         /*                          */
  321.     {                                                                           /*                          */
  322.       ComSettings [Com] . Parity = InkeyChr - 48;                               /*                          */
  323.       ResetPort = TRUE;                                                         /*                          */
  324.     }                                                                           /*                          */
  325.   printf ("Select number of stop bits [%u]: ", ComSettings [Com] . Stop);       /*-Set the number of stop   */
  326.   do                                                                            /* bits to use              */
  327.     {                                                                           /*                          */
  328.       InkeyChr = (byte) getch ();                                               /*                          */
  329.     } while (((InkeyChr < 49) | (InkeyChr > 50)) & (InkeyChr != 0x0D));         /*                          */
  330.   printf ("%c\n\n", (byte) InkeyChr);                                           /*                          */
  331.   if (InkeyChr != 0x0D)                                                         /*                          */
  332.     {                                                                           /*                          */
  333.       ComSettings [Com] . Stop = InkeyChr - 48;                                 /*                          */
  334.       ResetPort = TRUE;                                                         /*                          */
  335.     }                                                                           /*                          */
  336.   printf ("Select number of data bits [%u]: ", ComSettings [Com] . Bits);       /*-Set the number of data   */
  337.   do                                                                            /* bits to use              */
  338.     {                                                                           /*                          */
  339.       InkeyChr = (byte) getch ();                                               /*                          */
  340.     } while (((InkeyChr < 53) | (InkeyChr > 56)) & (InkeyChr != 0x0D));         /*                          */
  341.   printf ("%c\n\n", (byte) InkeyChr);                                           /*                          */
  342.   if (InkeyChr != 0x0D)                                                         /*                          */
  343.     {                                                                           /*                          */
  344.       ComSettings [Com] . Bits = InkeyChr - 48;                                 /*                          */
  345.       ResetPort = TRUE;                                                         /*                          */
  346.     }                                                                           /*                          */
  347.   if (ResetPort)                                                                /*-If any of the settings   */
  348.     SetupRS232 (Com, ComSettings [Com] . Baud,                                  /* have changed, reset the  */
  349.                      ComSettings [Com] . Parity,                                /* port                     */
  350.                      ComSettings [Com] . Stop,                                  /*                          */
  351.                      ComSettings [Com] . Bits);                                 /*                          */
  352. }                                                                               /*                          */
  353.                                                                                 /*                          */
  354. /* This provides a simple terminal emulation that might be used to prove that these routines really work,   */
  355. /* that they are not hard to use. I got to playing, and perhaps it got a bit more complex than necessary... */
  356. /* but then again, who said it had to be quick and dirty.  The LocalEcho parameter determines if characters */
  357. /* typed on the keyboard should be echoed to the screen.                                                    */
  358.                                                                                 /*                          */
  359. void TTY (enum Boolean LocalEcho)                                               /*                          */
  360. {                                                                               /*                          */
  361.   enum Boolean ExitTTY;                                                         /*-TRUE when ready to quit  */
  362.   enum Boolean DataReady;                                                       /*-TRUE if buffer not empty */
  363.   enum Boolean OldCarrier [2];                                                  /*-Detects Carrier change   */
  364.   byte Buffer [3];                                                              /*-Character buffer string  */
  365.                                                                                 /*                          */
  366.   OldCarrier [0] = ! Carrier [0];                                               /*-Force Carrier Detect     */
  367.   OldCarrier [1] = ! Carrier [1];                                               /* status to be displayed   */
  368.   DataReady = FALSE;                                                            /*                          */
  369.   ExitTTY = FALSE;                                                              /*                          */
  370.   clrscr ();                                                                    /*                          */
  371.   puts ("Terminal emulator commands\n");                                        /*-Brief summary of command */
  372.   puts ("<ALT C>  Toggle Port in use COM1/2");                                  /* keys that can be used    */
  373.   puts ("<Alt E>  Toggle Local Echo On/Off");                                   /*                          */
  374.   puts ("<Alt P>  Change Port Parameters");                                     /*                          */
  375.   puts ("<Alt X>  Exit\n");                                                     /*                          */
  376.   printf ("%u port(s) available\n", MaxPorts);                                  /*                          */
  377.   do                                                                            /*-Terminal emulation start */
  378.     {                                                                           /*                          */
  379.       disable ();                                                               /*-If data is received,     */
  380.       DataReady = (InTail [CurrentCom] != InHead [CurrentCom]);                 /* print it one char per    */
  381.       enable ();                                                                /* pass through the loop    */
  382.       if (DataReady)                                                            /*                          */
  383.         {                                                                       /*                          */
  384.           disable ();                                                           /*                          */
  385.           Buffer [0] = InBuffer [CurrentCom] [InHead [CurrentCom]];             /*                          */
  386.           InHead [CurrentCom] = (InHead [CurrentCom] + 1) % MaxSize;            /*                          */
  387.           enable ();                                                            /*                          */
  388.           switch (Buffer [0])                                                   /*                          */
  389.             {                                                                   /*                          */
  390.                case 12 : clrscr ();                                             /*-Formfeed clears the      */
  391.                          break;                                                 /* terminal screen          */
  392.                default : putch (Buffer [0]);                                    /*                          */
  393.                          break;                                                 /*                          */
  394.             }                                                                   /*                          */
  395.         }                                                                       /*                          */
  396.       if (OldCarrier [CurrentCom] != Carrier [CurrentCom])                      /*-Display any changes in   */
  397.         {                                                                       /* Carrier Detect status    */
  398.           if (Carrier [CurrentCom])                                             /*                          */
  399.             printf ("\nCARRIER DETECTED (COM%u)\n", CurrentCom + 1);            /*                          */
  400.           else                                                                  /*                          */
  401.             printf ("\nNO CARRIER (COM%u)\n", CurrentCom + 1);                  /*                          */
  402.           OldCarrier [CurrentCom] = Carrier [CurrentCom];                       /*                          */
  403.         }                                                                       /*                          */
  404.       if (kbhit ())                                                             /*-If a key has been pushed */
  405.         {                                                                       /* then process it          */
  406.           Buffer [0] = getch();                                                 /*                          */
  407.           if ((Buffer [0] == 0) && kbhit())                                     /*-Extended key codes need  */
  408.             {                                                                   /* another read             */
  409.               Buffer [0] = getch();                                             /*                          */
  410.               switch (Buffer [0])                                               /*-Process function keys    */
  411.                 {                                                               /*                          */
  412.                   case 46 : if (((CurrentCom + 1) % 2 ) < MaxPorts)             /*-<ALT C> lets you toggle  */
  413.                               {                                                 /* between ports if both    */
  414.                                 CurrentCom = (CurrentCom + 1) % 2;              /* ports exist              */
  415.                                 printf ("\nCOM%u\n", CurrentCom + 1);           /*                          */
  416.                               }                                                 /*                          */
  417.                             else                                                /*                          */
  418.                               {                                                 /*                          */
  419.                                 printf ("\nCOM%u not available\n", 1+(CurrentCom + 1) % 2); /*              */
  420.                               }                                                 /*                          */
  421.                             break;                                              /*                          */
  422.                   case 18 : LocalEcho = ! LocalEcho;                            /*-<ALT E> toggles duplex   */
  423.                             break;                                              /*                          */
  424.                   case 25 : SetUpPort (CurrentCom);                             /*-<ALT P> for port setup   */
  425.                             break;                                              /*                          */
  426.                   case 45 : ExitTTY = TRUE;                                     /*-<ALT X> exits emulation  */
  427.                             break;                                              /*                          */
  428.                   default : Buffer [1] = Buffer [0];                            /*-All other function keys  */
  429.                             Buffer [0] = '\x1B';                                /* are passed through to    */
  430.                             Buffer [2] = '\x00';                                /* the port                 */
  431.                             WriteCOM (CurrentCom, Buffer);                      /*                          */
  432.                             break;                                              /*                          */
  433.                 }                                                               /*                          */
  434.             }                                                                   /*                          */
  435.           else                                                                  /*-Normal keys are sent or  */
  436.             {                                                                   /* translated and then sent */
  437.               Buffer [1] = '\x00';                                              /*                          */
  438.               switch (Buffer [0])                                               /*                          */
  439.                 {                                                               /*                          */
  440.                    case 12 : if (LocalEcho) clrscr ();                          /*-FormFeed clears screen   */
  441.                              break;                                             /* if local echo is on      */
  442.                    case 13 : Buffer [1] = '\x0A';                               /*-Linefeed added to <CR>   */
  443.                              Buffer [2] = '\x00';                               /*                          */
  444.                              if (LocalEcho) puts ("");                          /*                          */
  445.                              break;                                             /*                          */
  446.                    default : if (LocalEcho) putch (Buffer [0]);                 /*                          */
  447.                              break;                                             /*-All other characters are */
  448.                 }                                                               /* sent as typed            */
  449.               WriteCOM (CurrentCom, Buffer);                                    /*                          */
  450.             }                                                                   /*-Send the buffered data   */
  451.         }                                                                       /*                          */
  452.     } while (! ExitTTY);                                                        /*                          */
  453. }                                                                               /*-Continue emulation until */
  454.                                                                                 /* <ALT X> is pressed       */
  455. main ()                                                                         /*                          */
  456. {                                                                               /*                          */
  457.   clrscr ();                                                                    /*                          */
  458.   atexit ((atexit_t) RemoveIntOnExit);                                          /*-VERY IMPORTANT!          */
  459.   MaxPorts = (biosequip () & 0x0E00) >> 9;                                      /*-How many ports there are */
  460.   IntInstalled [0] = FALSE;                                                     /*-No interrupt handlers    */
  461.   IntInstalled [1] = FALSE;                                                     /* are installed yet        */
  462.   ComSettings [0] . Baud = B9600;                                               /*-Define COM1 default      */
  463.   ComSettings [0] . Parity = None;                                              /* protocol settings        */
  464.   ComSettings [0] . Stop = 1;                                                   /*                          */
  465.   ComSettings [0] . Bits = 8;                                                   /*                          */
  466.   ComSettings [1] . Baud = B2400;                                               /*-Define COM2 default      */
  467.   ComSettings [1] . Parity = None;                                              /* protocol settings        */
  468.   ComSettings [1] . Stop = 1;                                                   /*                          */
  469.   ComSettings [1] . Bits = 8;                                                   /*                          */
  470.   if (MaxPorts > 0)                                                             /*-If COM1 exists:          */
  471.     {                                                                           /*                          */
  472.       SetupRS232 (0, ComSettings [0] . Baud,                                    /*-Initialize COM1 to the   */
  473.                      ComSettings [0] . Parity,                                  /* default settings         */
  474.                      ComSettings [0] . Stop,                                    /*                          */
  475.                      ComSettings [0] . Bits);                                   /*                          */
  476.       InstallInt (0);                                                           /*-Install the interrupt    */
  477.     }                                                                           /*                          */
  478.   else puts ("Error!  No serial ports installed in this computer");             /*                          */
  479.   if (MaxPorts > 1)                                                             /*-If COM2 exists:          */
  480.     {                                                                           /*                          */
  481.       SetupRS232 (1, ComSettings [1] . Baud,                                    /*-Initialize COM2 to the   */
  482.                      ComSettings [1] . Parity,                                  /* default settings         */
  483.                      ComSettings [1] . Stop,                                    /*                          */
  484.                      ComSettings [1] . Bits);                                   /*                          */
  485.       InstallInt (1);                                                           /*-Install the interrupt    */
  486.     }                                                                           /*                          */
  487.   CurrentCom = 0;                                                               /*-Set COM1 as logged port  */
  488.   TTY (FALSE);                                                                  /*-TTY with local echo off  */
  489.                                                                                 /*                          */
  490. /* IMPORTANT:  RemoveIntOnExit is always called when the program terminates! */ /*-RemoveIntOnExit invoked  */
  491.                                                                                 /* by Turbo C.  Don't exit  */
  492. }                                                                               /* w/o removing interrupts! */
  493.